home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 19 / Amiga Plus Leser CD 19.iso / Tools / Freeware / Swf_Player / Lib / graphic_generic.cc < prev    next >
Encoding:
C/C++ Source or Header  |  2002-11-17  |  29.6 KB  |  1,281 lines

  1. ////////////////////////////////////////////////////////////
  2. // Flash Plugin and Player
  3. // Copyright (C) 1998 Olivier Debon
  4. // 
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. // 
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. // 
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18. // 
  19. ///////////////////////////////////////////////////////////////
  20. //  Author : Olivier Debon  <odebon@club-internet.fr>
  21. //  
  22.  
  23. #include "swf.h"
  24.  
  25. extern unsigned char SQRT[];
  26.  
  27. #define FULL_AA
  28.  
  29. #define PRINT 0
  30.  
  31. typedef unsigned short TYPE;
  32.  
  33. static char cmp8[256];    // 8bit colormap
  34.  
  35. long
  36. allocColor15(Color color)
  37. {
  38.     return (color.red >> 3)<<10 | (color.green>>3)<<5 | (color.blue>>3);
  39. }
  40.  
  41. #if 0
  42. long
  43. allocColor16_646(Color color)
  44. {
  45.     return (color.red >> 2)<<10 | (color.green>>4)<<6 | (color.blue>>2);
  46. }
  47. #endif
  48.  
  49. long
  50. allocColor16_565(Color color)
  51. {
  52.     return (color.red >> 3)<<11 | (color.green>>2)<<5 | (color.blue>>3);
  53. }
  54.  
  55. long
  56. allocColor24_32(Color color)
  57. {
  58.     return (color.red)<<16 | (color.green)<<8 | color.blue;
  59. }
  60.  
  61. long
  62. allocColor8(Color color)
  63. {
  64.     return cmp8[(color.red>>6)<<4 | (color.green>>6)<<2 | (color.blue>>6)];
  65. }
  66.  
  67. // Public
  68.  
  69. GraphicDevice::GraphicDevice(FlashDisplay *fd)
  70. {
  71.     int depth;
  72.  
  73.     flashDisplay = fd;
  74.  
  75.     bgInitialized = 0;
  76.  
  77.     // Reset flash refresh flag
  78.     flashDisplay->flash_refresh = 0;
  79.  
  80.         /* 16 bits, RGB565 */
  81.     redMask = 0xF800;
  82.     greenMask = 0x07E0;
  83.     blueMask = 0x001F;
  84.         bpp = 2;
  85.         depth = 16;
  86.  
  87.         /* should be the actual window size */
  88.     targetWidth = fd->width;
  89.     targetHeight = fd->height;
  90.         bpl = fd->bpl;
  91.  
  92. #if PRINT
  93.     printf("Target Width  = %d\n", targetWidth);
  94.     printf("Target Height = %d\n", targetHeight);
  95. #endif
  96.  
  97.     zoom = FRAC;
  98.     movieWidth = targetWidth;
  99.     movieHeight = targetHeight;
  100.  
  101.     viewPort.xmin = 0;
  102.     viewPort.xmax = targetWidth-1;
  103.     viewPort.ymin = 0;
  104.     viewPort.ymax = targetHeight-1;
  105.  
  106.     switch (bpp) {
  107.         case 1:
  108.             allocColor = allocColor8;
  109.             redMask = 0xe0;
  110.             greenMask = 0x18;
  111.             blueMask = 0x07;
  112.             break;
  113.         case 2:
  114.             if (depth == 16) {
  115.                 allocColor = allocColor16_565;
  116.             } else
  117.             if (depth == 15) {
  118.                 allocColor = allocColor15;
  119.             }
  120.             break;
  121.         case 3:
  122.         case 4:
  123.             allocColor = allocColor24_32;
  124.             break;
  125.     }
  126.  
  127.     canvasBuffer = (unsigned char *) fd->pixels;
  128.  
  129.     adjust = new Matrix;
  130.     foregroundColor.red = 0;
  131.     foregroundColor.green = 0;
  132.     foregroundColor.blue = 0;
  133.     foregroundColor.alpha = ALPHA_OPAQUE;
  134.  
  135.     backgroundColor.red = 0;
  136.     backgroundColor.green = 0;
  137.     backgroundColor.blue = 0;
  138.     backgroundColor.alpha = ALPHA_OPAQUE;
  139.  
  140.     showMore = 0;
  141.  
  142.     setClipping(0);    // Reset
  143.     setClipping(1);
  144.  
  145.         /* polygon rasterizer : handle memory errors ! */
  146.  
  147.         height = targetHeight;
  148.         segs = (Segment **)malloc(height * sizeof(Segment *));
  149.         memset(segs, 0, height * sizeof(Segment *));
  150.         ymin = height;
  151.         ymax = -1;
  152.  
  153.         seg_pool = (Segment *)malloc(NB_SEGMENT_MAX * sizeof(Segment));
  154.         seg_pool_cur = seg_pool;
  155. }
  156.  
  157. GraphicDevice::~GraphicDevice()
  158. {
  159.     free(segs);
  160.     free(seg_pool);
  161.     
  162.     if (adjust) {
  163.         delete adjust;
  164.     }
  165. }
  166.  
  167. ///////////// PLATFORM INDEPENDENT
  168. Color *
  169. GraphicDevice::getColormap(Color *old, long n, Cxform *cxform)
  170. {
  171.     Color *newCmp;
  172.  
  173.     newCmp = new Color[n];
  174.     if (newCmp == NULL) return NULL;
  175.  
  176.     if (cxform) {
  177.         for(long i = 0; i < n; i++)
  178.         {
  179.             newCmp[i] = cxform->getColor(old[i]);
  180.             newCmp[i].pixel = allocColor(newCmp[i]);
  181.         }
  182.     } else {
  183.         for(long i = 0; i < n; i++)
  184.         {
  185.             newCmp[i].pixel = allocColor(old[i]);
  186.         }
  187.     }
  188.  
  189.     return newCmp;
  190. }
  191.  
  192. ///////////// PLATFORM INDEPENDENT
  193. long
  194. GraphicDevice::getHeight()
  195. {
  196.     return targetHeight;
  197. }
  198.  
  199. ///////////// PLATFORM INDEPENDENT
  200. long
  201. GraphicDevice::getWidth()
  202. {
  203.     return targetWidth;
  204. }
  205.  
  206. ///////////// PLATFORM INDEPENDENT
  207. Color
  208. GraphicDevice::getForegroundColor()
  209. {
  210.     return foregroundColor;
  211. }
  212.  
  213. void
  214. GraphicDevice::setForegroundColor(Color color)
  215. {
  216.     foregroundColor = color;
  217. }
  218.  
  219. ///////////// PLATFORM INDEPENDENT
  220. Color
  221. GraphicDevice::getBackgroundColor()
  222. {
  223.     return backgroundColor;
  224. }
  225.  
  226. ///////////// PLATFORM INDEPENDENT
  227. int
  228. GraphicDevice::setBackgroundColor(Color color)
  229. {
  230.     if (bgInitialized == 0) {
  231.         backgroundColor = color;
  232.         clearCanvas();
  233.         bgInitialized = 1;
  234.         return 1;
  235.     }
  236.     return 0;
  237. }
  238.  
  239. ///////////// PLATFORM INDEPENDENT
  240. void
  241. GraphicDevice::setMovieDimension(long width, long height)
  242. {
  243.     float xAdjust, yAdjust;
  244.  
  245.     movieWidth = width;
  246.     movieHeight = height;
  247.  
  248.     xAdjust = (float)targetWidth*zoom/(float)width;
  249.     yAdjust = (float)targetHeight*zoom/(float)height;
  250.  
  251.     if (xAdjust < yAdjust) {
  252.         adjust->a = xAdjust;
  253.         adjust->d = xAdjust;
  254.                 adjust->ty = ((targetHeight*zoom) - (long)(height * xAdjust))/2;
  255.         viewPort.ymin = adjust->ty/zoom;
  256.         viewPort.ymax = targetHeight-viewPort.ymin-1;
  257.     } else {
  258.         adjust->a = yAdjust;
  259.         adjust->d = yAdjust;
  260.                 adjust->tx = ((targetWidth*zoom) - (long)(width * yAdjust))/2;
  261.         viewPort.xmin = adjust->tx/zoom;
  262.         viewPort.xmax = targetWidth-viewPort.xmin-1;
  263.     }
  264.  
  265.     if (viewPort.xmin < 0) viewPort.xmin = 0;
  266.     if (viewPort.ymin < 0) viewPort.ymin = 0;
  267.     if (viewPort.xmax >= targetWidth) viewPort.xmax = targetWidth-1;
  268.     if (viewPort.ymax >= targetHeight) viewPort.ymax = targetHeight-1;
  269. }
  270.  
  271. ///////////// PLATFORM INDEPENDENT
  272. void
  273. GraphicDevice::setMovieZoom(int z)
  274. {
  275.     z *= FRAC;
  276.     if (z <= 0 || z > 100) return;
  277.     zoom = z;
  278.     setMovieDimension(movieWidth,movieHeight);
  279. }
  280.  
  281. ///////////// PLATFORM INDEPENDENT
  282. void
  283. GraphicDevice::setMovieOffset(long x, long y)
  284. {
  285.     adjust->tx = -zoom*x;
  286.     adjust->ty = -zoom*y;
  287. }
  288.  
  289. ///////////// PLATFORM INDEPENDENT
  290. void
  291. GraphicDevice::clearCanvas()
  292. {
  293.     TYPE  pixel;
  294.     TYPE *point,*p;
  295.     long                 h, w,n;
  296.  
  297.     if (!bgInitialized) return;
  298.  
  299.     pixel = allocColor(backgroundColor);
  300.  
  301.     point = (TYPE *)(canvasBuffer + clip_rect.ymin * bpl) + clip_rect.xmin;
  302.     w = clip_rect.xmax - clip_rect.xmin;
  303.     h = clip_rect.ymax - clip_rect.ymin;
  304.  
  305.     while (h--) {
  306.         p = point;
  307.         n = w;
  308.         while (n--) {
  309.             *p++ = pixel;
  310.         }
  311.  
  312.         point = (TYPE *)((char *)point + bpl);
  313.     }
  314.  
  315.     flashDisplay->flash_refresh = 1;
  316.     flashDisplay->clip_x = clip_rect.xmin;
  317.     flashDisplay->clip_y = clip_rect.ymin;
  318.     flashDisplay->clip_width  = clip_rect.xmax-clip_rect.xmin;
  319.     flashDisplay->clip_height = clip_rect.ymax-clip_rect.ymin;
  320. }
  321.  
  322. ///////////// PLATFORM INDEPENDENT
  323. long
  324. GraphicDevice::clip(long &y, long &start, long &end)
  325. {
  326.     long xmin,xend;
  327.  
  328.     if (y < clip_rect.ymin ||
  329.         y >= clip_rect.ymax) return 1;
  330.     if (end <= start)
  331.         return 1;
  332.     xmin = clip_rect.xmin * FRAC;
  333.     xend = clip_rect.xmax * FRAC;
  334.  
  335.     if (end <= xmin || start >= xend) return 1;
  336.  
  337.     if (start < xmin) start = xmin;
  338.     if (end > xend) end = xend;
  339.  
  340.     return 0;
  341. }
  342.  
  343. #define RED_MASK   0xF800
  344. #define GREEN_MASK 0x07E0
  345. #define BLUE_MASK  0x001F
  346.  
  347. /* alpha = 0 : select c1, alpha = 255 select c2 */
  348. static inline unsigned long
  349. mix_alpha(unsigned long c1, 
  350.                                       unsigned long c2, int alpha)
  351. {
  352.     long r1,r2,r;
  353.     long g1,g2,g;
  354.     long b1,b2,b;
  355.  
  356.     r1 = c1 & RED_MASK;
  357.     r2 = c2 & RED_MASK;
  358.     r = (((r2-r1)*alpha + r1 * 256) >> 8) & RED_MASK;
  359.  
  360.     g1 = c1 & GREEN_MASK;
  361.     g2 = c2 & GREEN_MASK;
  362.     g = (((g2-g1)*alpha + g1 * 256) >> 8) & GREEN_MASK;
  363.  
  364.     b1 = c1 & BLUE_MASK;
  365.     b2 = c2 & BLUE_MASK;
  366.     b = (((b2-b1)*alpha + b1 * 256) >> 8) & BLUE_MASK;
  367.  
  368.     return (r|g|b);
  369. }
  370.  
  371. void
  372. GraphicDevice::fillLineAA(FillStyleDef *f, long y, long start, long end)
  373. {
  374.     register long   n;
  375.     TYPE *line;
  376.     TYPE *point,pixel;
  377.     unsigned int alpha, start_alpha,end_alpha;
  378.     
  379.     if (clip(y,start,end)) return;
  380.     
  381.     line = (TYPE *)(canvasBuffer + bpl*y);
  382.     
  383.     alpha = f->color.alpha;
  384.     pixel = f->color.pixel;
  385.     
  386.     if (alpha == ALPHA_OPAQUE) {
  387.  
  388.         start_alpha = 255 - ((start & (FRAC-1)) << (8-FRAC_BITS));
  389.         end_alpha = (end & (FRAC-1)) << (8-FRAC_BITS);
  390.         
  391.         start >>= FRAC_BITS;
  392.         end >>= FRAC_BITS;
  393.         
  394.         point = &line[start];
  395.  
  396.         if (start == end) {
  397.             *point = mix_alpha(*point, pixel, start_alpha + end_alpha - 255);
  398.         } else {
  399.             n = end-start;
  400.             if (start_alpha < 255) {
  401.                 *point = mix_alpha(*point, pixel, start_alpha);
  402.                 point++;
  403.                 n--;
  404.             }
  405.             while (n > 0) {
  406.                 *point = pixel;
  407.                 point++;
  408.                 n--;
  409.             }
  410.             if (end_alpha > 0) {
  411.                 *point = mix_alpha(*point, pixel, end_alpha);
  412.             }
  413.         }
  414.     } else {
  415.  
  416.         start_alpha = 255 - ((start & (FRAC-1)) << (8-FRAC_BITS));
  417.         end_alpha = (end & (FRAC-1)) << (8-FRAC_BITS);
  418.  
  419.         start >>= FRAC_BITS;
  420.         end >>= FRAC_BITS;
  421.         
  422.         point = &line[start];
  423.         
  424.         if (start == end) {
  425.             *point = mix_alpha(*point, pixel, 
  426.                                ((start_alpha + end_alpha - 255) * alpha) >> 8);
  427.         } else {
  428.             n = end-start;
  429.             if (start_alpha < 255) {
  430.                 *point = mix_alpha(*point, pixel, (start_alpha * alpha) >> 8);
  431.                 point++;
  432.                 n--;
  433.             }
  434.             while (n > 0) {
  435.                 *point = mix_alpha(*point, pixel, alpha);
  436.                 point++;
  437.                 n--;
  438.             }
  439.             if (end_alpha > 0) {
  440.                 *point = mix_alpha(*point, pixel, (end_alpha * alpha) >> 8);
  441.             }
  442.         }
  443.     }
  444. }
  445.  
  446. void
  447. GraphicDevice::fillLine(FillStyleDef *f, long y, long start, long end)
  448. {
  449.     register long   n;
  450.         TYPE *line,*point;
  451.         TYPE pixel;
  452.         unsigned int alpha;
  453.  
  454.     if (clip(y,start,end)) return;
  455.  
  456.         start >>= FRAC_BITS;
  457.         end >>= FRAC_BITS;
  458.  
  459.     line = (TYPE *)(canvasBuffer + bpl*y);
  460.     point = &line[start];            
  461.     n = end-start;                
  462.         pixel = f->color.pixel;
  463.         alpha = f->color.alpha;
  464.         if (alpha == ALPHA_OPAQUE) {
  465.             while (n--) { 
  466.         *point = pixel;
  467.         point++;            
  468.             }
  469.         } else {
  470.             while (n--) { 
  471.         *point = mix_alpha(*point, pixel, alpha);
  472.         point++;            
  473.             }
  474.         }
  475. }
  476.  
  477. /* 16 bit assumed... easy to change */
  478. void
  479. GraphicDevice::fillLineBitmap(FillStyleDef *f, long y, long start, long end)
  480. {
  481.     int n;
  482.     long x1,y1,dx,dy;
  483.     Matrix *m = &f->bitmap_matrix;
  484.     Bitmap *b = f->bitmap;
  485.     unsigned char *pixels;
  486.     TYPE *p;
  487.     Color *cmap;
  488.     long pixbpl;
  489.     TYPE pixel;
  490.     int offset;
  491.     unsigned char *alpha_table;
  492.  
  493.     /* safety test) */
  494.     if (!b) return;
  495.  
  496.     if (clip(y,start,end)) return;
  497.     
  498.     start /= FRAC;
  499.     end /= FRAC;
  500.     n = end - start;
  501.     p = (TYPE *) (this->canvasBuffer + this->bpl*y + start * 2);
  502.     
  503.     /* the coordinates in the image are normalized to 16 bits */
  504.     x1 = (long) (m->a * start + m->b * y + m->tx);
  505.     y1 = (long) (m->c * start + m->d * y + m->ty);
  506.     dx = (long) (m->a);
  507.     dy = (long) (m->c);
  508.     
  509.     pixels = b->pixels;
  510.     pixbpl = b->bpl;
  511.     cmap = f->cmap;
  512.  
  513.     if (b->alpha_buf == NULL) {
  514.         while (n) {
  515.             if (x1 >= 0 && y1 >= 0 && 
  516.                 (x1 >> 16) < b->width && (y1 >> 16) < b->height) {
  517.                 
  518.                 pixel = cmap[pixels[(y1 >> 16) * pixbpl + (x1 >> 16)]].pixel;
  519.                 *p = pixel;
  520.             }
  521.             x1 += dx;
  522.             y1 += dy;
  523.             p++;
  524.             n--;
  525.         }
  526.     } else if (f->alpha_table) {
  527.         alpha_table = f->alpha_table;
  528.         while (n) {
  529.             if (x1 >= 0 && y1 >= 0 && 
  530.                 (x1 >> 16) < b->width && (y1 >> 16) < b->height) {
  531.                 
  532.                 offset = (y1 >> 16) * pixbpl + (x1 >> 16);
  533.                 pixel = cmap[pixels[offset]].pixel;
  534.                 *p = mix_alpha(*p, pixel, alpha_table[b->alpha_buf[offset]]);
  535.             }
  536.             x1 += dx;
  537.             y1 += dy;
  538.             p++;
  539.             n--;
  540.         }
  541.     } else {
  542.         while (n) {
  543.             if (x1 >= 0 && y1 >= 0 && 
  544.                 (x1 >> 16) < b->width && (y1 >> 16) < b->height) {
  545.                 
  546.                 offset = (y1 >> 16) * pixbpl + (x1 >> 16);
  547.                 pixel = cmap[pixels[offset]].pixel;
  548.                 *p = mix_alpha(*p, pixel, b->alpha_buf[offset]);
  549.             }
  550.             x1 += dx;
  551.             y1 += dy;
  552.             p++;
  553.             n--;
  554.         }
  555.     }
  556. }
  557.  
  558. void
  559. GraphicDevice::fillLineLG(Gradient *grad, long y, long start, long end)
  560. {
  561.     long dr,r,v,r2;
  562.     register long n;
  563.     TYPE *line;
  564.     TYPE *point;
  565.         Color *cp,*ramp;
  566.         Matrix *m = &grad->imat;
  567.         unsigned int start_alpha,end_alpha;
  568.  
  569.     if (clip(y,start,end)) return;
  570.  
  571.         start_alpha = 255 - ((start & (FRAC-1)) << (8-FRAC_BITS));
  572.         end_alpha = (end & (FRAC-1)) << (8-FRAC_BITS);
  573.         
  574.     start /= FRAC;
  575.     end /= FRAC;
  576.  
  577.     n = end-start;
  578.  
  579.         r = (long) (m->a * start + m->b * y + m->tx);
  580.         dr = (long) (m->a);
  581.  
  582.         ramp = grad->ramp;
  583.  
  584.         line = (TYPE *)(canvasBuffer + bpl*y);
  585.     point = &line[start];    
  586.  
  587.         r2 = r + n * dr;
  588.         if ( ((r | r2) & ~255) == 0 ) {
  589.             if (!grad->has_alpha) {
  590. #ifdef FULL_AA
  591.         if (start_alpha < 255) {
  592.                     v = r>>16;
  593.                     *point = mix_alpha(*point, (TYPE)ramp[v].pixel, start_alpha);
  594.                     point++;
  595.                     r += dr;
  596.             n--;
  597.         }
  598. #endif /* FULL_AA */
  599.                 while (n>0) {
  600.                     v = r>>16;
  601.                     *point = (TYPE)ramp[v].pixel;    
  602.                     point++;                
  603.                     r += dr;                
  604.             n--;
  605.                 }
  606. #ifdef FULL_AA
  607.         if (end_alpha > 0) {
  608.                     v = r>>16;
  609.                     *point = mix_alpha(*point, (TYPE)ramp[v].pixel, end_alpha);
  610.         }
  611. #endif /* FULL_AA */
  612.             } else {
  613.                 while (n--) {
  614.                     v = r>>16;
  615.                     cp = &ramp[v];
  616.                     *point = mix_alpha(*point, cp->pixel, cp->alpha);
  617.                     point++;
  618.                     r += dr;
  619.                 }
  620.             }
  621.         } else {
  622.             if (!grad->has_alpha) {
  623. #ifdef FULL_AA
  624.         if (start_alpha < 255) {
  625.                     v = r>>16;
  626.                     if (v < 0) v = 0;
  627.                     else if (v > 255) v = 255;
  628.                     *point = mix_alpha(*point, (TYPE)ramp[v].pixel, start_alpha);
  629.                     point++;
  630.                     r += dr;
  631.             n--;
  632.         }
  633. #endif /* FULL_AA */
  634.                 while (n>0) {
  635.                     v = r>>16;
  636.                     if (v < 0) v = 0;
  637.                     else if (v > 255) v = 255;
  638.                     *point = (TYPE)ramp[v].pixel;    
  639.                     point++;                
  640.                     r += dr;                
  641.             n--;
  642.                 }
  643. #ifdef FULL_AA
  644.         if (end_alpha > 0) {
  645.                     v = r>>16;
  646.                     if (v < 0) v = 0;
  647.                     else if (v > 255) v = 255;
  648.                     *point = mix_alpha(*point, (TYPE)ramp[v].pixel, end_alpha);
  649.         }
  650. #endif /* FULL_AA */
  651.             } else {
  652.                 while (n--) {
  653.                     v = r>>16;
  654.                     if (v < 0) v = 0;
  655.                     else if (v > 255) v = 255;
  656.                     cp = &ramp[v];
  657.                     *point = mix_alpha(*point, cp->pixel, cp->alpha);
  658.                     point++;
  659.                     r += dr;
  660.                 }
  661.             }
  662.         }
  663. }
  664.  
  665. ///////////// PLATFORM INDEPENDENT
  666. void
  667. GraphicDevice::fillLineRG(Gradient *grad, long y, long start, long end)
  668. {
  669.     long X,dx,r,Y,dy;
  670.     long dist2;
  671.     register long   n;
  672.         Color *cp,*ramp;
  673.     TYPE *line;                            
  674.     TYPE *point;                            
  675.         Matrix *m = &grad->imat;
  676.         unsigned int start_alpha,end_alpha;
  677.  
  678.     if (clip(y,start,end)) return;
  679.  
  680.         start_alpha = 255 - ((start & (FRAC-1)) << (8-FRAC_BITS));
  681.         end_alpha = (end & (FRAC-1)) << (8-FRAC_BITS);
  682.         
  683.     start /= FRAC;
  684.     end /= FRAC;
  685.  
  686.     n = end-start;
  687.         
  688.         X = (long) (m->a * start + m->b * y + m->tx);
  689.         Y = (long) (m->c * start + m->d * y + m->ty);
  690.         dx = (long) (m->a);
  691.         dy = (long) (m->c);
  692.  
  693.         ramp = grad->ramp;
  694.                                     
  695.     line = (TYPE *)(canvasBuffer + bpl*y);
  696.     point = &line[start];
  697.                  
  698.         if (!grad->has_alpha) {
  699. #ifdef FULL_AA
  700.         if (start == end) {
  701.             dist2 = ((X>>16)*(X>>16))+((Y>>16)*(Y>>16));
  702.             if ((unsigned long)dist2 >= 65536) {
  703.                 r = 255;                    
  704.             } else {                        
  705.                 r= SQRT[dist2];    
  706.             }
  707.             *point = mix_alpha(*point, (TYPE)ramp[r].pixel, start_alpha + end_alpha - 255);
  708.         } else {
  709.             if (start_alpha < 255) {
  710.             dist2 = ((X>>16)*(X>>16))+((Y>>16)*(Y>>16));
  711.             if ((unsigned long)dist2 >= 65536) {
  712.                 r = 255;                    
  713.             } else {                        
  714.                 r= SQRT[dist2];    
  715.             }
  716.             *point = mix_alpha(*point, (TYPE)ramp[r].pixel, start_alpha);
  717.             point++;
  718.             X += dx;                        
  719.             Y += dy;                        
  720.             n--;
  721.             }
  722. #endif /* FULL_AA */
  723.             while (n>0) {                    
  724.             dist2 = ((X>>16)*(X>>16))+((Y>>16)*(Y>>16));
  725.             if ((unsigned long)dist2 >= 65536) {
  726.                 r = 255;                    
  727.             } else {                        
  728.                 r= SQRT[dist2];    
  729.             }
  730.             *point = (TYPE)ramp[r].pixel;
  731.             point++;                     
  732.             X += dx;                        
  733.             Y += dy;                        
  734.             n--;
  735.             }        
  736. #ifdef FULL_AA
  737.             if (end_alpha > 0) {
  738.             dist2 = ((X>>16)*(X>>16))+((Y>>16)*(Y>>16));
  739.             if ((unsigned long)dist2 >= 65536) {
  740.                 r = 255;                    
  741.             } else {                        
  742.                 r= SQRT[dist2];    
  743.             }
  744.             *point = mix_alpha(*point, (TYPE)ramp[r].pixel, end_alpha);
  745.             }
  746.         }
  747. #endif /* FULL_AA */
  748.  
  749.         } else {
  750.             while (n--) {                    
  751.         dist2 = ((X>>16)*(X>>16))+((Y>>16)*(Y>>16));
  752.         if ((unsigned long)dist2 >= 65536) {
  753.                     r = 255;                    
  754.         } else {                        
  755.                     r= SQRT[dist2];    
  756.         }
  757.                 cp = &ramp[r];
  758.         *point = mix_alpha(*point, cp->pixel, cp->alpha);
  759.         point++;
  760.         X += dx;                        
  761.         Y += dy;                        
  762.             }        
  763.         }
  764. }
  765.  
  766. void
  767. GraphicDevice::drawBox(long x1, long y1, long x2, long y2)
  768. {
  769.     int i;
  770.  
  771.     for(i=0;i<FRAC*2;i++) {
  772.         drawLine(x1+i, y1+i, x2-i, y1+i, 0);
  773.         drawLine(x1+i, y2-i, x2-i, y2-i, 0);
  774.  
  775.         drawLine(x1+i, y1+i+1, x1+i, y2-i-1, 0);
  776.         drawLine(x2-i, y1+i+1, x2-i, y2-i-1, 0);
  777.     }
  778. }
  779.  
  780. void
  781. GraphicDevice::drawLine(long x1, long y1, long x2, long y2, long width)
  782. {
  783.     int n,adr,dx,dy,sx,color;
  784.     register int a;
  785.     register TYPE *pp;
  786.     int alpha;
  787.  
  788.     x1 = (x1) >> FRAC_BITS;
  789.     y1 = (y1) >> FRAC_BITS;
  790.     x2 = (x2) >> FRAC_BITS;
  791.     y2 = (y2) >> FRAC_BITS;
  792.     
  793.     if (y1 > y2 || (y1 == y2 && x1 > x2)) {
  794.         long tmp;
  795.  
  796.         tmp=x1;
  797.         x1=x2;
  798.         x2=tmp;
  799.  
  800.         tmp=y1;
  801.         y1=y2;
  802.         y2=tmp;
  803.     }
  804.  
  805.     if (y1 == y2 && (y1 < clip_rect.ymin || y1 > clip_rect.ymax)) return;
  806.     if (x1 == x2 && (x1 < clip_rect.xmin || x1 > clip_rect.xmax)) return;
  807.     if (x1 == x2 && y1 == y2) return;    // Bad !!!
  808.  
  809.     if (y1 < clip_rect.ymin && y1 != y2) {
  810.     x1 += (x2-x1)*(clip_rect.ymin-y1)/(y2-y1);
  811.     y1 = clip_rect.ymin;
  812.     }
  813.  
  814.     if (y2 > clip_rect.ymax && y1 != y2) {
  815.     x2 -= (x2-x1)*(y2-clip_rect.ymax)/(y2-y1);
  816.     y2 = clip_rect.ymax;
  817.     }
  818.  
  819.     if (x1 < x2) {
  820.         if (x1 < clip_rect.xmin && x1 != x2) {
  821.         y1 += (y2-y1)*(clip_rect.xmin-x1)/(x2-x1);
  822.         x1 = clip_rect.xmin;
  823.         }
  824.  
  825.         if (x2 > clip_rect.xmax && x1 != x2) {
  826.         y2 -= (y2-y1)*(x2-clip_rect.xmax)/(x2-x1);
  827.         x2 = clip_rect.xmax;
  828.         }
  829.     }
  830.  
  831.     if (x1 > x2) {
  832.         if (x2 < clip_rect.xmin && x2 != x1) {
  833.         y2 -= (y2-y1)*(clip_rect.xmin-x2)/(x1-x2);
  834.         x2 = clip_rect.xmin;
  835.         }
  836.  
  837.         if (x1 > clip_rect.xmax && x2 != x1) {
  838.         y1 += (y2-y1)*(x1-clip_rect.xmax)/(x1-x2);
  839.         x1 = clip_rect.xmax;
  840.         }
  841.     }
  842.  
  843.     // Check again
  844.     if (x1 == x2 && y1 == y2) return;
  845.     if (x1 < clip_rect.xmin || x2 < clip_rect.xmin) return;
  846.     if (y1 < clip_rect.ymin || y2 < clip_rect.ymin) return;
  847.     if (x1 > clip_rect.xmax || x2 > clip_rect.xmax) return;
  848.     if (y1 > clip_rect.ymax || y2 > clip_rect.ymax) return;
  849.  
  850.     sx=bpl >> 1;
  851.     adr=(y1 * sx + x1);
  852.     pp = (TYPE *)canvasBuffer + adr;
  853.     
  854.     dx = x2 - x1;
  855.     dy = y2 - y1;
  856.  
  857.     color = allocColor(foregroundColor);
  858.     alpha = foregroundColor.alpha;
  859.  
  860.     if (alpha == ALPHA_OPAQUE) {
  861.  
  862. #define PUTPIXEL()                 \
  863.   {                        \
  864.       *pp=color;                        \
  865.   }
  866.  
  867. #define DRAWLINE(dx,dy,inc_1,inc_2) \
  868.     n=dx;\
  869.     a=2*dy-dx;\
  870.     dy=2*dy;\
  871.     dx=2*dx-dy;\
  872.      do {\
  873.       PUTPIXEL();\
  874.             if (a>0) { pp+=(inc_1); a-=dx; }\
  875.             else { pp+=(inc_2); a+=dy; }\
  876.      } while (--n >= 0);
  877.  
  878. /* fin macro */
  879.  
  880.   if (dx == 0 && dy == 0) {
  881.     PUTPIXEL();
  882.   } else if (dx > 0) {
  883.     if (dx >= dy) {
  884.       DRAWLINE(dx, dy, sx + 1, 1);
  885.     } else {
  886.       DRAWLINE(dy, dx, sx + 1, sx);
  887.     }
  888.   } else {
  889.     dx = -dx;
  890.     if (dx >= dy) {
  891.       DRAWLINE(dx, dy, sx - 1, -1);
  892.     } else {
  893.       DRAWLINE(dy, dx, sx - 1, sx);
  894.     }
  895.   }
  896.  
  897.  
  898. #undef DRAWLINE
  899. #undef PUTPIXEL
  900.     } else {
  901. #define PUTPIXEL()                 \
  902.   {                        \
  903.       *pp=mix_alpha(*pp,color,alpha);            \
  904.   }
  905.  
  906. #define DRAWLINE(dx,dy,inc_1,inc_2) \
  907.     n=dx;\
  908.     a=2*dy-dx;\
  909.     dy=2*dy;\
  910.     dx=2*dx-dy;\
  911.      do {\
  912.       PUTPIXEL();\
  913.             if (a>0) { pp+=(inc_1); a-=dx; }\
  914.             else { pp+=(inc_2); a+=dy; }\
  915.      } while (--n >= 0);
  916.  
  917. /* fin macro */
  918.  
  919.   if (dx == 0 && dy == 0) {
  920.     PUTPIXEL();
  921.   } else if (dx > 0) {
  922.     if (dx >= dy) {
  923.       DRAWLINE(dx, dy, sx + 1, 1);
  924.     } else {
  925.       DRAWLINE(dy, dx, sx + 1, sx);
  926.     }
  927.   } else {
  928.     dx = -dx;
  929.     if (dx >= dy) {
  930.       DRAWLINE(dx, dy, sx - 1, -1);
  931.     } else {
  932.       DRAWLINE(dy, dx, sx - 1, sx);
  933.     }
  934.   }
  935.  
  936.  
  937. #undef DRAWLINE
  938. #undef PUTPIXEL
  939.     }
  940. }
  941.  
  942. /************************************************************************/
  943.  
  944. /* polygon rasteriser */
  945.  
  946. inline Segment *
  947. GraphicDevice::allocSeg()
  948. {
  949.     Segment *seg;
  950.  
  951.     if ( (seg_pool_cur - seg_pool) >= NB_SEGMENT_MAX )
  952.         return NULL;
  953.     seg = seg_pool_cur++;
  954.  
  955.     return seg;
  956. }
  957.  
  958. /* add a segment to the current path */
  959. void
  960. GraphicDevice::addSegment(long x1, long y1, long x2, long y2,
  961.                           FillStyleDef *f0,
  962.                           FillStyleDef *f1,
  963.                           int aa)
  964. {
  965.     Segment *seg,**segs;
  966.     long dX, X, Y, ymin, ymax, tmp;
  967.     FillStyleDef *ff;
  968.  
  969.     if ( y1 == y2 ) {
  970.         return;
  971.     }
  972.  
  973.     if (y1 < y2) {
  974.         ymin = y1;
  975.         ymax = y2;
  976.         ff = f0;
  977.         f0 = f1;
  978.         f1 = ff;
  979.     } else {
  980.         ymin = y2;
  981.         ymax = y1;
  982.         tmp = x1;
  983.         x1 = x2;
  984.         x2 = tmp;
  985.     }
  986.  
  987.     if (ymax>>FRAC_BITS < clip_rect.ymin) {
  988.         return;
  989.     }
  990.     if (ymin>>FRAC_BITS > clip_rect.ymax) {
  991.         return;
  992.     }
  993.  
  994.     X = x1 << SEGFRAC;
  995.     dX = ((x2 - x1)<<SEGFRAC)/(ymax-ymin);
  996.  
  997.     if (ymin < 0) {
  998.         X += dX * (-ymin);
  999.         ymin = 0;
  1000.     }
  1001.  
  1002.     Y = (ymin + (FRAC-1)) & ~(FRAC-1);
  1003.     if (Y > ymax) {
  1004.         //printf("Elimine @ y = %d   ymin = %d, ymax = %d\n", Y, ymin, seg->ymax);
  1005.         return;
  1006.     }
  1007.     X += dX * (Y-ymin);
  1008.  
  1009.     Y >>= FRAC_BITS;
  1010.     if (Y >= clip_rect.ymax) {
  1011.         return;
  1012.     }
  1013.  
  1014.     seg = allocSeg();
  1015.     if (seg == NULL) {
  1016.         return;
  1017.     }
  1018.  
  1019.     seg->next = 0;
  1020.     seg->nextValid = 0;
  1021.     seg->aa = aa;
  1022.     seg->ymax = ymax;
  1023.     seg->x1 = x1;
  1024.     seg->x2 = x2;
  1025.     seg->X = X;
  1026.     seg->dX = dX;
  1027.     seg->fs[0] = f0;
  1028.     seg->fs[1] = f1;
  1029.  
  1030.     if (Y < this->ymin) this->ymin = Y;
  1031.     ymax = (seg->ymax + FRAC - 1) >> FRAC_BITS;
  1032.     if (ymax >= this->height) ymax = this->height-1;
  1033.     if (ymax > this->ymax) this->ymax = ymax;
  1034.  
  1035.     segs = this->segs;
  1036.  
  1037.     if (segs[Y] == 0) {
  1038.         segs[Y] = seg;
  1039.     } else {
  1040.         Segment *s,*prev;
  1041.  
  1042.         prev = 0;
  1043.         for(s = segs[Y]; s; prev = s, s = s->next) {
  1044.             if (s->X > seg->X) {
  1045.                 if (prev) {
  1046.                     prev->next = seg;
  1047.                     seg->next = s;
  1048.                 } else {
  1049.                     seg->next = segs[Y];
  1050.                     segs[Y] = seg;
  1051.                 }
  1052.                 break;
  1053.             }
  1054.         }
  1055.         if (s == 0) {
  1056.             prev->next = seg;
  1057.             seg->next = s;
  1058.         }
  1059.     }
  1060. }
  1061.  
  1062. inline Segment *
  1063. GraphicDevice::progressSegments(Segment * curSegs, long y)
  1064. {
  1065.     Segment *seg,*prev;
  1066.  
  1067.     // Update current segments
  1068.     seg = curSegs;
  1069.     prev = 0;
  1070.     while(seg)
  1071.     {
  1072.         if ((y*FRAC) > seg->ymax) {
  1073.             // Remove this segment, no more valid
  1074.             if (prev) {
  1075.                 prev->nextValid = seg->nextValid;
  1076.             } else {
  1077.                 curSegs = seg->nextValid;
  1078.             }
  1079.             seg = seg->nextValid;
  1080.         } else {
  1081.             seg->X += seg->dX * FRAC;
  1082.             prev = seg;
  1083.             seg = seg->nextValid;
  1084.         }
  1085.     }
  1086.     return curSegs;
  1087. }
  1088.  
  1089. inline Segment *
  1090. GraphicDevice::newSegments(Segment *curSegs, Segment *newSegs)
  1091. {
  1092.     Segment *s,*seg,*prev;
  1093.  
  1094.     s = curSegs;
  1095.     prev = 0;
  1096.  
  1097.     // Check for new segments
  1098.     for (seg = newSegs; seg; seg=seg->next)
  1099.     {
  1100.         // Place it at the correct position according to X
  1101.         if (curSegs == 0) {
  1102.             curSegs = seg;
  1103.             seg->nextValid = 0;
  1104.         } else {
  1105.             for(; s; prev = s, s = s->nextValid)
  1106.             {
  1107.                 if ( s->X > seg->X ||
  1108.                      ( (s->X == seg->X) && 
  1109.                        ( (seg->x1 == s->x1 && seg->dX < s->dX) ||
  1110.                          (seg->x2 == s->x2 && seg->dX > s->dX)
  1111.                          ))) {
  1112.                     // Insert before s
  1113.                     if (prev) {
  1114.                         seg->nextValid = s;
  1115.                         prev->nextValid = seg;
  1116.                     } else {
  1117.                         seg->nextValid = curSegs;
  1118.                         curSegs = seg;
  1119.                     }
  1120.                     break;
  1121.                 }
  1122.             }
  1123.             // Append at the end
  1124.             if (s == 0) {
  1125.                 prev->nextValid = seg;
  1126.                 seg->nextValid = 0;
  1127.             }
  1128.         }
  1129.  
  1130.         s = seg;
  1131.     }
  1132.  
  1133.     return curSegs;
  1134. }
  1135.  
  1136. #if 0
  1137. static void
  1138. printSeg(Segment *seg)
  1139. {
  1140.     /*
  1141.     printf("Seg %08x : X = %5d, Ft = %d, Cl = %2x/%2x/%2x, Cr = %2x/%2x/%2x, x1=%5d, x2=%5d, ymin=%5d, ymax=%5d\n", seg,
  1142.         seg->X>>SEGFRAC,
  1143.         seg->right ? seg->right->type: -1,
  1144.         seg->left ? seg->left->color.red : -1,
  1145.         seg->left ? seg->left->color.green : -1,
  1146.         seg->left ? seg->left->color.blue : -1,
  1147.         seg->right ? seg->right->color.red : -1,
  1148.         seg->right ? seg->right->color.green : -1,
  1149.         seg->right ? seg->right->color.blue : -1,
  1150.         seg->x1, seg->x2, seg->ymin, seg->ymax);
  1151.     */
  1152. }
  1153. #endif
  1154.  
  1155. inline void
  1156. GraphicDevice::renderScanLine(long y, Segment *curSegs)
  1157. {
  1158.     Segment *seg;
  1159.     long width;
  1160.     int fi = 1;
  1161.     FillStyleDef *f;
  1162.  
  1163.     width = targetWidth * FRAC;
  1164.  
  1165.     if (curSegs && curSegs->fs[0] && curSegs->fs[1] == 0) {
  1166.         fi = 0;
  1167.     }
  1168.     for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid)
  1169.     {
  1170.         if (seg->nextValid->X <0) continue;
  1171.         if ((seg->X>>SEGFRAC) > width) break;
  1172.         f = seg->fs[fi];
  1173.         if (f) {
  1174.             switch (f->type) {
  1175.                 case f_Solid:
  1176.                     if (seg->aa) {
  1177.                         fillLineAA(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  1178.                     } else  {
  1179.                         fillLine(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  1180.                     }
  1181.                     break;
  1182.                 case f_TiledBitmap:
  1183.                 case f_clippedBitmap:
  1184.                     fillLineBitmap(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  1185.                     break;
  1186.                 case f_LinearGradient:
  1187.                     fillLineLG(&f->gradient, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  1188.                     break;
  1189.                 case f_RadialGradient:
  1190.                     fillLineRG(&f->gradient, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  1191.                     break;
  1192.             case f_None:
  1193.             break;
  1194.             }
  1195.         }
  1196.     }
  1197. }
  1198.  
  1199. /* draw the current path */
  1200. void
  1201. GraphicDevice::drawPolygon(void)
  1202. {
  1203.     long y;
  1204.     Segment *curSegs,*seg;
  1205.  
  1206.     // no segments ? 
  1207.     if (this->ymax == -1)
  1208.         return;
  1209.  
  1210.     // Foreach scanline
  1211.     curSegs = 0;
  1212.     for(y=this->ymin; y <= this->ymax; y++) {
  1213.         
  1214.         // Make X values progess and remove unuseful segments
  1215.         curSegs = progressSegments(curSegs, y);
  1216.         
  1217.         // Add the new segment starting at the y position.
  1218.         curSegs = newSegments(curSegs, this->segs[y]);
  1219.         
  1220.         // Render the scanline
  1221.         if (this->scan_line_func == NULL) {
  1222.             renderScanLine(y, curSegs);
  1223.         } else {
  1224.             for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid) {
  1225.                 if (seg->nextValid->X >= seg->X) {
  1226.                     scan_line_func(this->scan_line_func_id, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  1227.                 }
  1228.             }
  1229.         }
  1230.     }
  1231.  
  1232.     /* free the segments */
  1233.     memset(this->segs + this->ymin, 0, 
  1234.            (this->ymax - this->ymin + 1) * sizeof(Segment *)); 
  1235.         
  1236.     this->ymax = -1;
  1237.     this->ymin = this->height;
  1238.  
  1239.     this->seg_pool_cur = this->seg_pool;
  1240. }
  1241.  
  1242. void
  1243. GraphicDevice::updateClippingRegion(Rect *rect)
  1244. {
  1245.     if (!clipping) return;
  1246.  
  1247.     transformBoundingBox(&clip_rect, adjust, rect, 1);
  1248.     clip_rect.xmin >>= FRAC_BITS;
  1249.     clip_rect.xmax >>= FRAC_BITS;
  1250.     clip_rect.ymin >>= FRAC_BITS;
  1251.     clip_rect.ymax >>= FRAC_BITS;
  1252.  
  1253.     clip_rect.xmin-=2;
  1254.     clip_rect.ymin-=2;
  1255.     clip_rect.xmax+=2;
  1256.     clip_rect.ymax+=2;
  1257.  
  1258.     if (clip_rect.xmin < viewPort.xmin) clip_rect.xmin = viewPort.xmin;
  1259.     if (clip_rect.xmax < viewPort.xmin) clip_rect.xmax = viewPort.xmin;
  1260.     if (clip_rect.ymin < viewPort.ymin) clip_rect.ymin = viewPort.ymin;
  1261.     if (clip_rect.ymax < viewPort.ymin) clip_rect.ymax = viewPort.ymin;
  1262.  
  1263.     if (clip_rect.xmax > viewPort.xmax) clip_rect.xmax = viewPort.xmax;
  1264.     if (clip_rect.ymax > viewPort.ymax) clip_rect.ymax = viewPort.ymax;
  1265.     if (clip_rect.xmin > viewPort.xmax) clip_rect.xmin = viewPort.xmax;
  1266.     if (clip_rect.ymin > viewPort.ymax) clip_rect.ymin = viewPort.ymax;
  1267. }
  1268.  
  1269. void
  1270. GraphicDevice::setClipping(int value)
  1271. {
  1272.     clipping = value;
  1273.     if (clipping == 0) {
  1274.         // Reset region
  1275.         clip_rect.xmin = viewPort.xmin;
  1276.         clip_rect.xmax = viewPort.xmax;
  1277.         clip_rect.ymin = viewPort.ymin;
  1278.         clip_rect.ymax = viewPort.ymax;
  1279.     }
  1280. }
  1281.